#include <ProcessThread/ProcessThread.h>
#include <Kernel/GlobalData.h>
#include <Memory/Heap.h>

/*
@brief 创建线程 TCB
*/

LPThreadControlBlock SimpleCreateThread
(
    DWORD dwUserStackSize,
    LPTHREAD_START_ROUTINE lpStartAddress,
    LPVOID lpParameter,
    DWORD dwCreationFlags
)
{
    /*
    * 线程隶属于进程，进程在创建之后，同时也一定会创建一条 main 线程
    * 线程的创建一定是在一条已经存在的线程运行中完成的
    */
    /* 找到当前正在运行的线程（创建线程一定会进入内核态，使用内核栈，内核栈栈底即当前线程 TCB） */
    LPThreadControlBlock lpCurrentThread = (LPVOID)((DWORD)&lpCurrentThread & 0xFFFFE000); /* trick：在栈帧上创建一个局部变量，取该局部变量的地址，由该地址确定当前栈帧 */
    /* 创建、分配内核栈时，一定要确保物理页框被分配，通过 HEAP_ZERO_MEMORY 确保这一点 */
    LPThreadControlBlock lpNewThread;
    DWORD dwPages = (dwUserStackSize - 1) / PAGE_SIZE + 1; /* 用户栈所需的页面数量 */
    lpNewThread = AllocateStackForUser(dwPages); /* 分配内核栈，大小为两个页面 */
    lpNewThread->lpUserStack = (LPVOID)((DWORD)lpNewThread + PAGE_SIZE * dwPages); /* 内核栈栈顶 */
    LPVOID lpBottomOfStack = AllocateStackForKernel();
    lpNewThread->lpKernelStack = (LPVOID)((DWORD)lpBottomOfStack + PAGE_SIZE * 2);
    lpNewThread->bIsIdle = FALSE; /* 非 IDLE 线程 */
    lpNewThread->context.dwCS = SELECTOR_USER_CODE;
    lpNewThread->context.dwDS = SELECTOR_USER_DATA;
    /* 创建、分配用户栈 */
    /* 默认大小为 2 页；若指定大小，则扩展为页大小的整数倍 */
    lpNewThread->lpParameter = lpParameter;
    lpNewThread->lpStartAddress = lpStartAddress;
    /* 将此 TCB 加入线程队列 */
    AppendTCBToQueue(g_lpReadyTCBQueue, lpNewThread);
}